"use strict";
let PDFDocment = require("pdfkit");
let Enumerable = require("linq");
let BaseRender = require("./BaseRender");
let BaseStyleRender = require("./BaseStyleRender");

/**
 *普通数据源样式渲染
 *
 * @class NormalDataStyleRender
 * @extends {BaseStyleRender}
 */
class NormalDataStyleRender extends BaseStyleRender {
    /**
     *渲染
     *
     * @memberof BaseStyleRender
     */
    _render() {
        this._renderControls();
        this._renderPageNum();
    }

    /**
     *获取当前样式
     *
     * @returns
     * @memberof BaseStyleRender
     */
    _getCurrentStyle() {
        this._itemIndex++;
        let pageSetting = this._pageSetting;
        var addHeight =
            pageSetting.height / pageSetting.reportCount *
            (this._itemIndex % pageSetting.reportCount);
        var style = this._deepCopy(this._style);
        if (this._itemIndex !== 0) {
            if (addHeight !== 0) {
                Enumerable.from(style.controls.texts).forEach(
                    text => text.rect.top += addHeight
                );
                Enumerable.from(style.controls.tables).forEach(
                    table => table.top += addHeight
                );
            }
            if (
                pageSetting.reportCount === 1 && this._itemIndex !== 0 ||
                this._itemIndex > pageSetting.reportCount - 1 &&
                    this._itemIndex % pageSetting.reportCount === 0
            ) {
                this._doc.addPage();
                this._pageNum++;
            }
        }
        if (pageSetting.showPageNum) {
            let pageNumText = Enumerable.from(
                style.controls.texts
            ).firstOrDefault(text => text.name === "pageNum");
            let itemPage = Enumerable.from(this._itemPages).firstOrDefault(
                item => item.pageNum === this._pageNum
            );
            if (itemPage) {
                itemPage.texts.push(pageNumText);
            } else {
                this._itemPages.push({
                    pageIndex: this._pageNum - 1,
                    texts: [pageNumText]
                });
            }
        }
        return style;
    }

    /**
     *渲染页码
     *
     * @memberof BaseStyleRender
     */
    _renderPageNum() {
        if (!this._pageSetting.showPageNum) return;
        let pageCount = this._itemIndex + 1;
        let num = 0;
        Enumerable.from(this._itemPages).forEach(item => {
            this._doc.switchToPage(item.pageIndex);
            Enumerable.from(item.texts).forEach(text => {
                num++;
                let value = text.text
                    .replace("@num", num)
                    .replace("@count", pageCount);
                this._renderText(value, {
                    left: text.rect.left,
                    top: text.rect.top,
                    width: text.rect.width,
                    align: text.align,
                    name: text.font.name,
                    size: text.font.size
                });
            });
        });
    }

    /**
     *渲染控件
     *
     * @param {*} tempData
     * @memberof NormalDataStyleRender
     */
    _renderControls(tempData) {
        let style = this._getCurrentStyle();
        Enumerable.from(style.controls.tables).forEach(table => {
            this._renderTable(table, tempData, style.controls.texts);
        });
    }

    /**
     *渲染表格
     *
     * @param {*} table
     * @param {*} tempData1
     * @param {*} texts
     * @memberof NormalDataStyleRender
     */
    _renderTable(table, tempData1, texts) {
        // 获取临时数据
        let tempData = this._getTempData(table, tempData1, texts);
        //渲染表头行
        this._renderHeaderRow(tempData);
        for (let i = 0; i < table.rows.length; i++) {
            let row = table.rows[i];
            if (row.isFixed || row.isHeader) continue;
            if (this._isDetailFieldRow(row)) {
                //渲染数据行
                let paging = this._data.dataGroupField
                    ? this._renderGroupDetailRow(row, tempData)
                    : this._renderDetailRow(row, tempData);
                if (paging) return;
                continue;
            }
            //渲染其他行
            this._renderRow(row, tempData);
        }
        // 渲染固定行
        Enumerable.from(tempData.fixedRows).forEach(row =>
            this._renderRow(row, tempData)
        );
        // 渲染Texts
        this._renderTexts(tempData);
    }

    /**
     *获取临时数据
     *
     * @param {*} table
     * @param {*} tempData1
     * @param {*} texts
     * @returns
     * @memberof NormalDataStyleRender
     */
    _getTempData(table, tempData1, texts) {
        let headerRow = Enumerable.from(table.rows).firstOrDefault(
            row => row.isHeader
        );
        let fixedRows = Enumerable.from(table.rows)
            .where(row => row.isFixed)
            .toArray();
        let fixedHeight = Enumerable.from(fixedRows).sum(row =>
            this._getRowHeight(row)
        );
        let tempData = {
            texts,
            headerRow,
            fixedRows,
            fixedHeight,
            renderHeight: 0,
            left: table.left,
            top: table.top,
            height: table.height,
            detailData:
                (tempData1 ? tempData1.detailData : null) ||
                this._data.detailData.itemList,
            isFixedRowHeight: table.isFixedRowHeight || false,
            fixedRowHeight: table.fixedRowHeight || 0,
            isFixedRowCount: table.isFixedRowCount || false,
            fixedRowCount: table.fixedRowCount || 0,
            dataGroupField: this._data.dataGroupField,
            renderWhiteRow: table.renderWhiteRow === false ? false : true
        };
        tempData.groups =
            (tempData1 ? tempData1.groups : null) ||
            this._groupDetailData(tempData);
        return tempData;
    }

    /**
     *数据分组
     *
     * @param {*} tempData
     * @returns
     * @memberof NormalDataStyleRender
     */
    _groupDetailData(tempData) {
        let groups = [];
        Enumerable.from(tempData.detailData)
            .groupBy(item => item[tempData.dataGroupField])
            .forEach(group => groups.push(group.getSource()));
        return groups;
    }

    /**
     *渲染表头行
     *
     * @param {*} tempData
     * @memberof NormalDataStyleRender
     */
    _renderHeaderRow(tempData) {
        let row = tempData.headerRow;
        let rowHeight = row.height || this._getRowHeight(row, null, true);
        let left = tempData.left;
        let top = tempData.top;
        Enumerable.from(row.cells).forEach(cell => {
            if (cell.isFather) {
                top = tempData.top;
            }
            this._renderTextAndRect(cell.text, {
                left,
                top,
                width: cell.width,
                height: cell.height || rowHeight,
                align: cell.align || "center",
                name: cell.font.name || "normal",
                isFixedRowHeight: tempData.isFixedRowHeight,
                size: cell.font.size,
                valign: cell.valign || "center"
            });
            if (cell.isFather) {
                top += cell.height;
            } else {
                left += cell.width;
            }
        });
        tempData.renderHeight += rowHeight;
        tempData.top += rowHeight;
    }

    /**
     *渲染数据行
     *
     * @param {*} row
     * @param {*} tempData
     * @memberof NormalDataStyleRender
     */
    _renderDetailRow(row, tempData) {
        let pageSetting = this._pageSetting;
        let detailData = this._deepCopy(tempData.detailData);
        let nextRowHeight = 0;
        for (let i = 0; i < detailData.length; i++) {
            let item = detailData[i];
            let rowHeight =
                nextRowHeight || this._getRowHeight(row, item, false, tempData);
            this._renderRow(row, tempData, rowHeight);
            tempData.detailData.splice(0, 1);
            if (tempData.isFixedRowCount) {
                if (
                    i === tempData.fixedRowCount - 1 &&
                    tempData.detailData.length !== 0
                ) {
                    // 渲染固定行
                    Enumerable.from(tempData.fixedRows).forEach(row =>
                        this._renderRow(row, tempData)
                    );
                    // 渲染Texts
                    this._renderTexts(tempData);
                    // 渲染剩余数据
                    this._renderControls(tempData);
                    return true;
                }
                // 如果渲染完毕,判断行数是否达到固定行数,若未达到则渲染空白行
                let count = tempData.fixedRowCount - (i + 1);
                if (
                    tempData.detailData.length === 0 &&
                    count !== 0 &&
                    tempData.renderWhiteRow
                ) {
                    for (let j = 0; j < count; j++) {
                        this._renderRow(
                            row,
                            tempData,
                            tempData.fixedRowHeight,
                            true
                        );
                    }
                }
                continue;
            }
            if (tempData.detailData.length === 0) break;
            nextRowHeight = this._getRowHeight(
                row,
                detailData[i + 1],
                false,
                tempData
            );
            if (
                tempData.height - tempData.renderHeight - tempData.fixedHeight <
                nextRowHeight
            ) {
                // 渲染固定行
                Enumerable.from(tempData.fixedRows).forEach(row =>
                    this._renderRow(row, tempData)
                );
                // 渲染Texts
                this._renderTexts(tempData);
                // 渲染剩余数据
                this._renderControls(tempData);
                return true;
            }
        }
        return false;
    }

    /**
     *渲染分组数据行
     *
     * @param {*} row
     * @param {*} tempData
     * @memberof NormalDataStyleRender
     */
    _renderGroupDetailRow(row, tempData) {
        let pageSetting = this._pageSetting;
        let groups = this._deepCopy(tempData.groups);
        let nextRowHeight = 0;
        let renderRowCount = 0;
        // 遍历分组
        for (let i = 0; i < groups.length; i++) {
            let items = groups[i];
            let defaultItem = items[0];
            let groupHeight = 0;
            // 遍历数据
            for (let j = 0; j < items.length; j++) {
                let item = items[j];
                let rowHeight =
                    nextRowHeight ||
                    this._getRowHeight(row, item, false, tempData);
                groupHeight += rowHeight;
                this._renderMergeRow(row, tempData, rowHeight);
                tempData.groups[0].splice(0, 1);
                renderRowCount++;
                // 若数据渲染完毕
                if (j === items.length - 1 && i === groups.length - 1) break;
                // 若固定行数 且 行数渲染满 且 数据还未渲染完毕
                if (
                    tempData.isFixedRowCount &&
                    renderRowCount === tempData.fixedRowCount
                ) {
                    // 渲染合并行
                    this._renderMergeRow(
                        row,
                        tempData,
                        groupHeight,
                        defaultItem
                    );
                    // 渲染固定行
                    Enumerable.from(tempData.fixedRows).forEach(row =>
                        this._renderRow(row, tempData)
                    );
                    // 渲染Texts
                    this._renderTexts(tempData);
                    // 渲染剩余数据
                    this._renderControls(tempData);
                    return true;
                }
                // 计算下一项行高 判断是否当页是否够渲染
                let nextItem =
                    j < items.length - 1 ? items[j + 1] : groups[i + 1][0];
                nextRowHeight = this._getRowHeight(
                    row,
                    nextItem,
                    false,
                    tempData
                );
                if (
                    tempData.height -
                        tempData.renderHeight -
                        tempData.fixedHeight <
                    nextRowHeight
                ) {
                    if (j === items.length - 1) tempData.groups.splice(0, 1);
                    // 渲染合并行
                    this._renderMergeRow(
                        row,
                        tempData,
                        groupHeight,
                        defaultItem
                    );
                    // 渲染固定行
                    Enumerable.from(tempData.fixedRows).forEach(row =>
                        this._renderRow(row, tempData)
                    );
                    // 渲染Texts
                    this._renderTexts(tempData);
                    // 渲染剩余数据
                    this._renderControls(tempData);
                    return true;
                }
            }
            // 渲染合并行
            this._renderMergeRow(row, tempData, groupHeight, defaultItem);
            tempData.groups.splice(0, 1);
        }
        return false;
    }

    /**
     *获取行高
     *
     * @param {*} row 行
     * @param {*} item 数据
     * @param {*} getbytext showtext来源
     * @param {*} tempData 临时数据
     * @returns
     * @memberof NormalDataStyleRender
     */
    _getRowHeight(row, item, getbytext, tempData) {
        let pageSetting = this._pageSetting;
        let rowHeight = pageSetting.fontSize + 9;
        let fixedRow = tempData && tempData.isFixedRowHeight;
        Enumerable.from(row.cells).forEach(cell => {
            cell.showtext = getbytext
                ? cell.text
                : item && this._isDetailField(cell)
                ? this._getDetailFieldValue(cell, item)
                : this._getMasterFieldValue(cell);
            // 合并行和固定行高 不参与行高计算
            if (cell.detailField && cell.detailField.mergeSameRow || fixedRow)
                return;
            let height =
                this._getTextHeight(cell.showtext, {
                    width: cell.width - 10,
                    align: cell.align,
                    size: cell.font.size
                }) + 9;
            if (height > rowHeight) rowHeight = height;
        });
        return fixedRow ? tempData.fixedRowHeight : rowHeight;
    }

    /**
     *渲染行
     *
     * @param {*} row
     * @param {*} tempData
     * @param {*} rowHeight
     * @param {*} isEmpty
     * @memberof NormalDataStyleRender
     */
    _renderRow(row, tempData, rowHeight, isEmpty) {
        let left = tempData.left;
        rowHeight = rowHeight || this._getRowHeight(row, null, null, tempData);
        Enumerable.from(row.cells).forEach(cell => {
            let showtext = isEmpty ? "" : cell.showtext;
            this._renderTextAndRect(showtext, {
                left,
                top: tempData.top,
                width: cell.width,
                height: rowHeight,
                align: cell.align || "left",
                name: cell.font.name || "normal",
                isFixedRowHeight: tempData.isFixedRowHeight,
                size: cell.font.size,
                valign: cell.valign
            });
            left += cell.width;
        });
        tempData.renderHeight += rowHeight;
        tempData.top += rowHeight;
    }

    /**
     *渲染合并行
     *
     * @param {*} row
     * @param {*} tempData
     * @param {*} rowHeight
     * @param {*} mergeItem 合并数据
     * @memberof NormalDataStyleRender
     */
    _renderMergeRow(row, tempData, rowHeight, mergeItem) {
        let left = tempData.left;
        rowHeight = rowHeight || this._getRowHeight(row);
        Enumerable.from(row.cells).forEach(cell => {
            if (
                mergeItem && !cell.detailField.mergeSameRow ||
                !mergeItem && cell.detailField.mergeSameRow
            ) {
                left += cell.width;
                return;
            }
            let showtext = mergeItem
                ? this._isDetailField(cell)
                    ? this._getDetailFieldValue(cell, mergeItem)
                    : this._getMasterFieldValue(cell)
                : cell.showtext;
            this._renderTextAndRect(showtext, {
                left,
                top: mergeItem ? tempData.top - rowHeight : tempData.top,
                width: cell.width,
                height: rowHeight,
                align: cell.align || "left",
                name: cell.font.name || "normal",
                isFixedRowHeight: tempData.isFixedRowHeight,
                size: cell.font.size,
                valign: cell.valign || (mergeItem ? "center" : "top")
            });
            left += cell.width;
        });
        if (!mergeItem) {
            tempData.renderHeight += rowHeight;
            tempData.top += rowHeight;
        }
    }
}

exports = module.exports = NormalDataStyleRender;
